package proxy

import (
	"sort"
	"strings"
	"sync"

	"gddgame.cc/galaxy/asteroid"
	"gddgame.cc/galaxy/binocle/logic"
	"gddgame.cc/galaxy/utils/uuid"
)

// asteroid的代理接口实现
// agent实现Worker接口
// core实现Router接口

type AgentProxy interface {
	LocalDC() string
}

type agentProxy struct {
	observer logic.Observer

	dc    string
	proxy string
	wan   string
}

func (proxy *agentProxy) Wan() string {
	return proxy.wan
}
func (proxy *agentProxy) Proxy() string {
	return proxy.proxy
}
func (proxy *agentProxy) IsLocal(wan string) bool {
	return wan == proxy.wan
}

func (proxy *agentProxy) Generate(keys []string) string {
	return strings.Join(keys, ";")
}

func (proxy *agentProxy) LocalDC() string {
	return proxy.dc
}

func newAgentProxy(observer logic.Observer, subscriber asteroid.Sub) *agentProxy {
	s := &agentProxy{
		observer: observer,
	}
	subscriber.On("proxy/info", func(message asteroid.Message) {
		//fmt.Println(message.GetFrom())
		s.proxy = message.GetFrom()
		s.wan = message.GetTarget()
	})

	observer.OnAllocTarget(func() {
		//fmt.Println("onAllocTarget")
		observer.PublishPipe().Send("proxy/apply")
	})
	return s
}

type DataCenter interface {
	DC() string
	Register(dataCenter string, wan string, groups []string)
	ListDC() []string
	GetWan(dataCenter string) string
}

type CoreProxy struct {
	watcher *logic.WatcherInstance
	dc      string
	wan     string

	groupMap    sync.Map
	dcWanMap    sync.Map
	groupWanMap *sync.Map

	dcs  []string
	wans []string
}

func (proxy *CoreProxy) DC() string {
	return proxy.dc
}

func (proxy *CoreProxy) Wans(info string) []string {
	if info != "" {
		if value, ok := proxy.groupWanMap.Load(info); ok {
			return value.([]string)
		}
		if value, ok := proxy.dcWanMap.Load(info); ok {
			return []string{value.(string)}
		}
		return []string{}
	} else {
		return proxy.wans
	}
}
func (proxy *CoreProxy) IsLocal(wan string) bool {
	return wan == proxy.wan
}

// 获取所有相关节点
func (proxy *CoreProxy) Resolve(key string) []string {
	if strings.Contains(key, ";") {
		// 多节点
		return strings.Split(key, ";")
	} else if strings.Contains(key, ":") {
		// 单节点
		return []string{key}
	} else {
		// 服务：按observer查找
		return []string{proxy.watcher.AllocNode(key, uuid.RandomString())}
	}
}

func (proxy *CoreProxy) Manager() DataCenter {
	return proxy
}

func (proxy *CoreProxy) Register(dc string, wan string, groups []string) {
	proxy.dcWanMap.Store(dc, wan)
	wans := []string{}
	dcs := []string{}
	proxy.dcWanMap.Range(func(key, value interface{}) bool {
		wans = append(wans, value.(string))
		dcs = append(dcs, key.(string))
		return true
	})
	proxy.groupMap.Store(dc, groups)
	g := &sync.Map{}
	proxy.groupMap.Range(func(key, value interface{}) bool {
		dc := key.(string)
		wan, ok := proxy.groupWanMap.Load(dc)
		if ok && wan != nil && wan.(string) != "" {
			for _, group := range value.([]string) {
				var list []string
				value, ok := g.Load(group)
				if !ok {
					list = []string{wan.(string)}
				} else {
					list = value.([]string)
					list = append(list, wan.(string))
				}
				sort.Strings(list)
				g.Store(group, list)
			}
		}
		return true
	})
	proxy.wans = wans
	proxy.dcs = dcs
	proxy.groupWanMap = g
}

func (proxy *CoreProxy) ListDC() []string {
	return proxy.dcs
}

func (proxy *CoreProxy) GetWan(dataCenter string) string {
	if value, ok := proxy.dcWanMap.Load(dataCenter); ok {
		return value.(string)
	}
	return ""
}

func newCoreProxy(dc string, wan string, watcher *logic.WatcherInstance, system logic.System) *CoreProxy {
	s := &CoreProxy{
		dc:      dc,
		wan:     wan,
		watcher: watcher,

		dcWanMap:    sync.Map{},
		groupMap:    sync.Map{},
		groupWanMap: &sync.Map{},

		dcs:  []string{},
		wans: []string{},
	}
	s.Register(dc, wan, nil)
	watcher.Watching("proxy/apply", func(message asteroid.Message) {
		//fmt.Println("accept proxy apply", message.GetOrigin())
		publisher := watcher.Observing(message.GetOrigin())
		if publisher != nil {
			//fmt.Println("send proxy info", message.GetOrigin())
			publisher.Direct(message.GetFrom()).TargetId(wan).Data(dc).Send("proxy/info")
		}
	})
	return s
}
